import cards
import sqlite3
import time
import random

def simulate_distributions(hole_cards, opponent_percentages, simulations = 100, community_cards = []):
    opponent_distributions = [best_hole_cards(len(opponent_percentages), percentage) for percentage in opponent_percentages]
    victories = 0
    card_deck = cards.card_deck()
    
    for _ in range(simulations):
        card_deck.reset()
        
        opponents_cards = [random.choice(opponent_distribution) for opponent_distribution in opponent_distributions]
        
        #print(opponents_cards)
        
        # Remove known cards
        for card in hole_cards + community_cards:
            card_deck.cards.remove(card)
        
        # Dealing the remaining community cards (we want 5)
        all_community_cards = community_cards + card_deck.deal_n_cards(5 - len(community_cards))
        
        # Comparing cards, we're assuming that we're winning (of course!)
        winning = True
        winners = 1
        my_power = cards.calc_cards_power(hole_cards + all_community_cards)
        for opponent_power in [cards.calc_cards_power(opponent_cards + all_community_cards) for opponent_cards in opponents_cards]:
            if opponent_power > my_power:
                winning = False
                break
            if opponent_power == my_power:
                winners += 1
        
        if winning:
            # One victory divided by the number of winners
            victories += 1/winners
            
    return victories/simulations

def simulate(hole_cards, num_opponents, simulations = 100, community_cards = []):
    victories = 0
    card_deck = cards.card_deck()
    
    for _ in range(simulations):
        card_deck.reset()
        
        # Remove known cards
        for card in hole_cards + community_cards:
            card_deck.cards.remove(card)
        
        # Dealing the remaining community cards (we want 5)
        all_community_cards = community_cards + card_deck.deal_n_cards(5 - len(community_cards))
        
        # Comparing cards, we're assuming that we're winning (of course!)
        winning = True
        winners = 1
        my_power = cards.calc_cards_power(hole_cards + all_community_cards)
        for opponent_power in [cards.calc_cards_power(card_deck.deal_n_cards(2) + all_community_cards) for _ in range(num_opponents)]:
            if opponent_power > my_power:
                winning = False
                break
            if opponent_power == my_power:
                winners += 1
        
        if winning:
            # One victory divided by the number of winners
            victories += 1/winners
            
    return victories/simulations

def count(pair, suited):
    if pair:
        return 6
    if suited:
        return 4
    
    return 12

def card_combinations(v1, v2, suited):
    if suited:
        # There are 4 combinations of two suited cards
        return [
                [[v1, 'C'], [v2, 'C']],
                [[v1, 'D'], [v2, 'D']],
                [[v1, 'H'], [v2, 'H']],
                [[v1, 'S'], [v2, 'S']]
        ]

    if v1 == v2:
        # There are 6 combinations of a pair
        return [
                [[v1, 'C'], [v1, 'D']],
                [[v1, 'C'], [v1, 'H']],
                [[v1, 'C'], [v1, 'S']],
                [[v1, 'D'], [v1, 'H']],
                [[v1, 'D'], [v1, 'S']],
                [[v1, 'H'], [v1, 'S']]
        ]
    
    # There are 12 combinations of two unsuited cards with different values
    return [
            [[v1, 'C'], [v2, 'D']],
            [[v1, 'C'], [v2, 'H']],
            [[v1, 'C'], [v2, 'S']],
            [[v1, 'D'], [v2, 'H']],
            [[v1, 'D'], [v2, 'S']],
            [[v1, 'H'], [v2, 'S']],
            [[v2, 'C'], [v1, 'D']],
            [[v2, 'C'], [v1, 'H']],
            [[v2, 'C'], [v1, 'S']],
            [[v2, 'D'], [v1, 'H']],
            [[v2, 'D'], [v1, 'S']],
            [[v2, 'H'], [v1, 'S']]
    ]

def best_hole_cards(opponents, percentage):
    conn = sqlite3.connect('hole_cards_100k_v2.db')
    c = conn.cursor()
    c.execute('SELECT * FROM probabilities WHERE opponents = %d ORDER BY probability DESC' % (opponents))
    
    hole_cards = []

    # We want the specified percentage of the total number of hole card combinations (which is (52 * 51)/2 = 1326)
    wanted_count = round(1326 * percentage)
    
    for row in c:
        new_cards = card_combinations(row[0], row[1], row[2])
        new_count = len(new_cards) + len(hole_cards)
        
        if new_count == wanted_count:
            hole_cards += new_cards
            break
        elif new_count > wanted_count:
            random.shuffle(new_cards)
            hole_cards += new_cards[:(wanted_count - len(hole_cards))]
            break
        else:
            hole_cards += new_cards
        
    return hole_cards

def generate_preflop_table(simulations, db_file):
    probabilities = []
    total_simulations = 0
        
    conn = sqlite3.connect(db_file)
    c = conn.cursor()
    c.execute("DELETE FROM probabilities")
    
    #probabilities(card1, card2, suited, opponents, probability, count)
    query_base = "INSERT INTO probabilities VALUES (?, ?, ?, ?, ?, ?)"
    
    for i in range(2, 15):
        for j in range(i, 15):
            for num_opponents in range(1, 10):
                print("Simulating " + str((i,j,num_opponents)) + "...")
                
                total_simulations += simulations
                c.execute(query_base, (i, j, 0, num_opponents, simulate([[i, 'H'],[j, 'C']], num_opponents, simulations), count(i == j, False)))
                conn.commit()
                
                if i != j:
                    total_simulations += simulations
                    c.execute(query_base, (i, j, 1, num_opponents, simulate([[i, 'H'],[j, 'H']], num_opponents, simulations), count(i == j, True)))
                    conn.commit()
    
    c.close()
    conn.close()
    
    return total_simulations

def main():
    start = time.time()
    total_simulations = generate_preflop_table(100000, 'hole_cards_100k_v2.db')
    execution_time = time.time() - start
    print("Execution time in seconds: " + str(execution_time))
    print("Total number of simulations: " + str(total_simulations))
    print("Simulations per second: " + str(total_simulations/execution_time))
    
if __name__ == '__main__':
    print(simulate_distributions([[2, 'H'], [7, 'C']], [0.01]))
    print(simulate([[2, 'H'], [7, 'C']], 1))